package com.ehotting.edsta.circuitDesign.gen.element.script;

import com.alibaba.fastjson.JSON;
import com.ehotting.edsta.circuitDesign.domain.EsCircuitCodeDataTemplate;
import com.ehotting.edsta.circuitDesign.domain.EsRuleScript;
import com.ehotting.edsta.circuitDesign.domain.EsSceneParam;
import com.ehotting.edsta.circuitDesign.gen.ScriptConstants;
import com.ehotting.edsta.circuitDesign.gen.element.bean.ConditionBean;
import com.ehotting.edsta.circuitDesign.gen.element.enums.ConditionTypeEnum;
import com.ehotting.edsta.circuitDesign.gen.element.enums.ScriptTypeEnum;
import com.ehotting.edsta.circuitDesign.gen.element.helper.ElementScriptHelper;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
public class ConditionElementScript extends ElementScriptAbstract {

    // -------------条件----------

    @Override
    public String invoke(EsRuleScript esRuleScript, List<EsCircuitCodeDataTemplate> inputParamList, List<EsSceneParam> outputParamList, String functionName) {

        List<ConditionBean> conditionList = setOrder(esRuleScript);
        outputParamList = findXElementList(conditionList, outputParamList);
        StringBuffer buf = new StringBuffer();

        // ------------------------------------脚本组装------------------------------------
        /**1、定义条件子方法 **/
        buf.append(createSubFunction(conditionList, outputParamList,functionName)).append(ScriptConstants.LINE);

        /**2、定义主方法 **/
        buf.append(createMainFunction(  outputParamList,  inputParamList, functionName));

        return  buf.toString();
    }


    private String createMainFunction(List<EsSceneParam> outputParamList, List<EsCircuitCodeDataTemplate> inputParamList,String functionName){
        StringBuffer buf = new StringBuffer();

        /**1、定义主方法头部 **/
        buf.append(functionStart( functionName, inputParamList));

        /**2、定义for循环 **/
        buf.append(startFor( outputParamList));
        int tab_index = outputParamList.size();

        /**3、执行条件 **/
        buf.append(runSubFunction( outputParamList, functionName,ScriptConstants.TAB(tab_index+1)))
                .append(ScriptConstants.LINE);

        /**4、定义for循环的结尾 **/
        buf.append(this.endFor(tab_index));

        /**5、处理结果 **/
        buf.append(this.handleResult(outputParamList));

        /**6、返回状态结果 **/
        buf.append( ScriptConstants.TAB + "return ElementReturnHelper.success();"+ ScriptConstants.LINE);

        /**7、方法结尾 **/
        buf.append( "};"+ ScriptConstants.LINE);

        return buf.toString();
    }


    /**
     * 处理结果值
     * @param outputParamList
     * @return
     */
    private String handleResult(List<EsSceneParam> outputParamList){
        StringBuffer buf = new StringBuffer();
        for (EsSceneParam esSceneParam : outputParamList) {
            buf.append( ScriptConstants.TAB);
            buf.append("ElementDataHelper.resetList(outMapList," + esSceneParam.getCode() + "List,\""+ esSceneParam.getCode() + "\");");
            buf.append( ScriptConstants.LINE);
        }
        return buf.toString();
    }


    /**
     * 根据priority从小到大排序
     * @param esRuleScript
     * @return
     */
    private List<ConditionBean> setOrder(EsRuleScript esRuleScript){
        List<ConditionBean> conditionList = JSON.parseArray(esRuleScript.getContent(),ConditionBean.class);
        conditionList = conditionList.stream().sorted(Comparator.comparing(ConditionBean::getPriority,
                Comparator.nullsFirst(Integer::compareTo)))
                .collect(Collectors.toList());
        return conditionList;
    }


    /**
     * 获取输出参数列表
     * @param conditionList
     * @param outputParamList
     * @return
     */
    private List<EsSceneParam> findXElementList(List<ConditionBean> conditionList,List<EsSceneParam> outputParamList){
        List<EsSceneParam> list = new ArrayList<>();
        for(EsSceneParam param : outputParamList){
            for(ConditionBean conditionBean : conditionList )
            if(conditionBean.getConditionScript().indexOf(param.getCode())!=-1
                    ||
                    conditionBean.getExecute().indexOf(param.getCode())!=-1){
                if(!list.contains(param)){
                    list.add(param);
                }

            }
        }
        return list;
    }


    /**
     * 创建子条件方法
     * @param conditionList
     * @param outputParamList
     * @param functionName
     * @return
     */
    private String createSubFunction(List<ConditionBean> conditionList, List<EsSceneParam> outputParamList, String functionName){
        StringBuffer buf = new StringBuffer();

        buf.append(defineSubFunctionHeader(outputParamList,functionName));

        buf.append(defineVar(conditionList, outputParamList));

        buf.append(defineBody(conditionList));

        buf.append(defineSetValue(conditionList,outputParamList));

        buf.append("};");
        buf.append(ScriptConstants.LINE);
        return buf.toString();
    }



    /**
     * 定义子方法头
     * @param outputParamList
     * @param functionName
     * @return
     */
    private String defineSubFunctionHeader(List<EsSceneParam> outputParamList, String functionName){
        StringBuffer buf = new StringBuffer();
        buf.append("def "+ getSubFunctionName(functionName));
        for (int i=0;i<outputParamList.size();i++){
            EsSceneParam esSceneParam = outputParamList.get(i);
            buf.append(esSceneParam.getCode()+"Obj");
            buf.append(",");
        }
        buf.append("outMapList");
        buf.append("){");
        buf.append(ScriptConstants.LINE);
        return buf.toString();
    }

    /***
     * 定义子方法变量并赋值
     * @param conditionList
     * @param outputParamList
     * @return
     */
    private String defineVar(List<ConditionBean> conditionList,List<EsSceneParam> outputParamList){
        StringBuffer buf = new StringBuffer();
        for (int i=0;i<outputParamList.size();i++){
            EsSceneParam esSceneParam = outputParamList.get(i);
            buf.append(ScriptConstants.TAB);
            buf.append( "double "+esSceneParam.getCode()+" = "+ esSceneParam.getCode() + "Obj.getValue()" +";");
            buf.append(ScriptConstants.LINE);
            for(ConditionBean conditionBean : conditionList){
                buf.append(this.getPropValue(esSceneParam,conditionBean.getConditionScript(),ScriptConstants.TAB));
                buf.append(this.getPropValue(esSceneParam,conditionBean.getExecute(),ScriptConstants.TAB));
            }
        }
        buf.append(ScriptConstants.LINE);
        return buf.toString();
    }

    /***
     * 定义子方法体
     * @param conditionList
     * @return
     */
    private String defineBody(List<ConditionBean> conditionList){
        StringBuffer buf = new StringBuffer();
        buf.append(ScriptConstants.TAB);
        for(ConditionBean conditionBean : conditionList){
            ConditionTypeEnum cType = ConditionTypeEnum.getObject(conditionBean.getConditionType());
            /**定义 if、else if、else语句**/
            buf.append(cType.getScript());
            if(cType == ConditionTypeEnum.IF || cType == ConditionTypeEnum.ELSE_IF) {
                buf.append("(").append(ElementScriptHelper.replaceNodeToUnderline(conditionBean.getConditionScript())).append(")");
            }
            /**定义执行语句**/
            buf.append("{").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2)).append(ElementScriptHelper.replaceNodeToUnderline(conditionBean.getExecute())).append(";").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB).append("}");
        }
        buf.append(ScriptConstants.LINE);
        return buf.toString();
    }

    /**
     * 定义设置方法
     * @param conditionList
     * @param outputParamList
     * @return
     */
    private String defineSetValue(List<ConditionBean> conditionList, List<EsSceneParam> outputParamList){
        StringBuffer buf = new StringBuffer();
        buf.append(setObjectValue(outputParamList));
        for(ConditionBean conditionBean : conditionList) {
            buf.append(setObjectProp(conditionBean.getExecute()));
        }
        return buf.toString();
    }

    /**
     * 设置对象值
     * @param outputParamList
     * @return
     */
    private String setObjectValue(List<EsSceneParam> outputParamList){
        StringBuffer buf = new StringBuffer();
        for ( int i=0;i<outputParamList.size();i++){
            EsSceneParam esSceneParam = outputParamList.get(i);
            buf.append(ScriptConstants.TAB);
            buf.append( "if( "+esSceneParam.getCode()+" != "+ esSceneParam.getCode() + "Obj.getValue()" +"){").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2));
            buf.append( "def newComponent =  ElementDataHelper.findByValue(allList,\""+esSceneParam.getCode()+"\","+esSceneParam.getCode()+");").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2));
            buf.append( "if(newComponent!=null){").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(3));
            buf.append( "ElementDataHelper.replace(outMapList,"+esSceneParam.getCode()+"Obj,newComponent,\""+esSceneParam.getCode()+"\");").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2)).append( "}").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB).append("}").append(ScriptConstants.LINE);
        }
        return buf.toString();
    }

    /**
     * 设置对象属性
     * @param content
     * @return
     */
    private String setObjectProp(String content){
        StringBuffer buf = new StringBuffer();
        Set<String> codeList = ElementScriptHelper.filter4Prop(content);
        for(String code : codeList){
            String[] cc = code.split("\\.");
            buf.append(ScriptConstants.TAB);
            buf.append("if(" + cc[0] + "Obj.getProps()!=null  && " + cc[0] + "Obj.getProps().get(\"" + cc[1] + "\")!=null){").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2));
            buf.append("if("+code.replaceAll("\\.", "_") + " == " + cc[0] + "Obj.prop(\"" + cc[1] + "\")){").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(3));
            buf.append( "def newComponent =  ElementDataHelper.findByProp(allList,\""+cc[0]+"\",\""+cc[1]+"\","+code.replaceAll("\\.", "_") +");");
            buf.append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(3));
            buf.append( "if(newComponent!=null){").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(4));
            buf.append( "ElementDataHelper.replace(outMapList,"+cc[0]+"Obj,newComponent,\""+cc[0]+"\");").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(3)).append("}").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB(2)).append("}").append(ScriptConstants.LINE);
            buf.append(ScriptConstants.TAB).append("}").append(ScriptConstants.LINE);
        }

        return buf.toString();
    }




    private String runSubFunction(List<EsSceneParam> outputParamList, String functionName, String TAB){
        StringBuffer buf = new StringBuffer();
        buf.append(TAB + getSubFunctionName(functionName));
        for ( int i=0;i<outputParamList.size();i++){
            EsSceneParam esSceneParam = outputParamList.get(i);
            buf.append(esSceneParam.getCode()+"Obj,");
        }
        buf.append("outMapList");
        buf.append(");");
        return buf.toString();
    }

    private String getSubFunctionName(String functionName){
        return functionName+"_sub(";
    }

    public boolean isTrue(ScriptTypeEnum code){
        return ScriptTypeEnum.CONDITION == code;
    }

    @Override
    public String getExample() {
        StringBuffer buf = new StringBuffer();
        buf.append("输入格式参数:");
        buf.append("输入条件格式，可以使用逻辑符号 \"&&\"、\"||\"分割:");
        buf.append("r1/r2 > 200 && r2.xx >= 200").append(ScriptConstants.LINE);
        buf.append("输入执行语句，多条使用分号分割\";\":");
        buf.append("r1 = 200 ; r2.xx = 200;").append(ScriptConstants.LINE);

        return buf.toString();
    }
}